define(function(require, exports, module) {

  // var Backbone = require('backbone');
  var $ = require('jquery');
  var _ = require('underscore');
  // var jsonview = require('jsonview');
  var tmpl = require('text!../tmpl.html');

  var THREE = require('three');
  var addReduce = require('hy5b/frontend/animation/add-reduce')
  var mathUtil = require('hy5b/math/index')
  var __ = require('hy5b/frontend/canvas/hline')

  function main() {
    var $app = $('<div id="app">');
    $('#main').html($app);

    $app.append(tmpl);

    app($app)
  }

  function app($app) {
    const w = 1280;
    const h = 720;
    const aspect = w / h;

    let params = {
      lightIntensity: [0.6, 0.1],
      cameraRZ: 150,
      cameraFrustumSize: 300,
      cameraPX: 200,
      cameraPY: 200,
      cameraPZ: 200
    };


    manualControlHelp();

    var camera, scene, renderer, light, drLight;
    var $canvas = $('<canvas width="512" height="512">');
    var rotation = 0;

    initRenderer();
    $('.webgl').append(renderer.domElement)
    initScene();
    initCamera();
    initLight();

    var geometry = new THREE.PlaneBufferGeometry(100, 100)
    var material = new THREE.MeshBasicMaterial({
      map: createTexture(),
      transparent: true
    })
    material.needsUpdate = true
    var mesh = new THREE.Mesh(geometry, material)
    scene.add(mesh);

    step();

    function createTexture() {
      $canvas.draw({
        fn: function(ctx) {
          ctx.clearRect(0, 0, 512, 512);
        }
      }).drawHLine({
        x: 256,
        y: 256,
        rotation: rotation
      });

      var texture = new THREE.CanvasTexture($canvas[0])
      return texture;
    }

    function initRenderer() {
      if (!renderer) {
        renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
        renderer.setSize(w, h);
        renderer.setClearColor(0x000000, 1.0);
        renderer.setPixelRatio(window.devicePixelRatio)

        // renderer.shadowMap.enabled = true;
        // renderer.shadowMapType = THREE.PCFSoftShadowMap;
      } else {
        renderer.setSize(w, h)
      }
      return renderer;
    }

    function initScene() {
      scene = new THREE.Scene()

      let axesHelper = new THREE.AxesHelper(500);
      scene.add(axesHelper);

      var helper = new THREE.GridHelper(1000, 100);
      helper.rotation.x = Math.PI / 2; //默认不是x,y平面
      helper.material.opacity = 0.25;
      helper.material.transparent = true;
      scene.add(helper);

      return scene;
    }

    function initCamera() {
      const frustumSize = params.cameraFrustumSize
      const near = 0.01;
      const far = mathUtil.vector3Length(params.cameraPX, params.cameraPY, params.cameraPZ) * 2;
      if (!camera) {
        camera = new THREE.OrthographicCamera(
        frustumSize * aspect / -2,
        frustumSize * aspect / 2,
        frustumSize / 2,
        frustumSize / -2, near, far)
      } else {
        camera.left = frustumSize * aspect / -2
        camera.right = frustumSize * aspect / 2
        camera.top = frustumSize / 2
        camera.bottom = frustumSize / -2
        camera.near = near
        camera.far = far
        camera.updateProjectionMatrix()
      }
      console.log('camera near:', near, 'far:', far, 'x*y:', frustumSize * aspect, 'x', frustumSize)
      camera.position.x = params.cameraPX
      camera.position.y = params.cameraPY
      camera.position.z = params.cameraPZ
      camera.lookAt(0,0,0)
      camera.rotation.z = params.cameraRZ * Math.PI / 180 //要在lookAt后
      return camera;
    }


    function initLight() {

      if (!light) {
        light = new THREE.AmbientLight(0xffffff);
        light.position.set(100, 100, 100)
        // scene.add(light)
      }
      
      if (!drLight) {
        drLight = new THREE.DirectionalLight(0xffffff, params.lightIntensity);
        // drLight.position.set(100, 100, 100).normalize() // normalize方法？
        drLight.position.set(100, 100, 100)

        if (1) {
          scene.add(drLight)
        } {
          // 课程22里面是这样的,不知道是为什么?说是模拟光是从相机的位置发出
          camera.add(drLight);
          camera.add(drLight.target);
          scene.add(camera);
        }
        
      } else {
        drLight.intensity = params.lightIntensity
      }
      
      
    }

    var timer;

    function step() {
      if (timer) {
        cancelAnimationFrame(timer)
      }
      timer = requestAnimationFrame(step);

      initCamera();

      initLight()

      if ($canvas) {
        $canvas.draw({
          fn: function(ctx) {
            ctx.clearRect(0, 0, 512, 512);
          }
        }).drawHLine({
          x: 256,
          y: 256,
          rotation: rotation
        });

      }

      material.needsUpdate = true
      material.map.needsUpdate = true

      render()

      rotation += 3;
    }


    function render() {
      renderer.render(scene, camera);
    }

    function manualControlHelp() {
      _.each(params, function(v, param) {
        let val = v;
        let delta;
        if (val.length > 0) {
          delta = val[1]
          val = val[0]
          params[param] = val
        }
        $app.append(
          addReduce({
            set: (function(param) {
              return function(value) {
                params[param] = value;
                step()
              }
            }(param)),
            key: param,
            val: val,
            delta: delta
          })
        )

        $app.append('<br/>')
      })
    }
  }

  return main;
})
